hashlib 模块提供了常见的摘要算法(也称为: 哈希算法,hash算法),如 MD5,SHA1 等等。

什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

摘要算法是不可逆的,就是不能通过已经使用 md5 加密过的值推导计算出原来的值

摘要算法的用途:
  • 密码的密文存储
  • 文件的一致性验证
    • 在下载的时候 检查我们下载的文件和远程服务器上的文件是否一致
    • 两台机器上的两个文件 你想检查这两个文件是否相等

1. md5 -> 推荐使用

  • .update(bytes) -> update方法所传入的值必须是 bytes 类型的加密内容

import hashlib

md5 = hashlib.md5()
md5.update(bytes('md5', encoding='utf-8'))  # 必须传入 bytes 类型的值
digest = md5.digest() # 获取加密后的值,以二进制的形式返回,且是bytes类型
print(digest)  # b'\x1b\xc2\x9b6\xf6#\xba\x82\xaa\xf6rO\xd3\xb1g\x18'
hexdigest = md5.hexdigest()  # 获取加密后的值,以十六进制的形式返回 -> 推荐使用
print(hexdigest)  # 1bc29b36f623ba82aaf6724fd3b16718

2. sha 系列

  • sha系列 随着算法复杂程度的增加所摘要的时间成本和空间成本(占内存)都会增加,但是其安全性比较高

import hashlib

md5 = hashlib.sha1()
md5.update(bytes('md5', encoding='utf-8'))
ciphertext = md5.hexdigest()
print(ciphertext)  # c1ea94f7e524679d0cf34ab7b0b28abe41ba732b

import hashlib

md5 = hashlib.sha224()
md5.update(bytes('md5', encoding='utf-8'))
ciphertext = md5.hexdigest()
print(ciphertext)  # 9f1a17462e4842ba55e6378178242a9a5e8840f83e2bf6c0e2faacc3

4.分次调用 update() 方法

  • 如果数据量很大,可以将内容分开分次调用update()
  • 将内容分开分次调用update() 和 将全部内容一次性传给update() 所得到的结果都是一样的

# 将内容分开分次调用update()

import hashlib

md5 = hashlib.md5()
md5.update(bytes('Hello ', encoding='utf-8'))
md5.update(bytes('World', encoding='utf-&'))
ciphertext = md5.hexdigest()
print(ciphertext)  # b10a8db164e0754105b7a99be72e3fe5

# 将全部内容一次性传给update()

import hashlib

md5 = hashlib.md5()
md5.update(bytes('Hello World', encoding='utf-8'))
ciphertext = md5.hexdigest()
print(ciphertext)  # b10a8db164e0754105b7a99be72e3fe5

5. 加盐

  • 加盐就是添加额外的内容与要加密的内容一起加密为了提交安全性,因为很多用户喜欢用123456,888888,password这些简单的口令,于是,黑客可以事先计算出这些常用口令的MD5值,得到一个反推表,这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号。

  • hashlib.md5(bytes('加盐的内容', encoding='utf-8')) -> 加盐的内容,且加盐的内容必须是bytes类型

import hashlib

md5 = hashlib.md5(bytes('加盐', encoding='utf-8'))  # 加盐的内容,且加盐的内容必须是bytes类型
md5.update(bytes('123456', encoding='utf-8'))  # 需要加密的内容
pwd = md5.hexdigest()
print(pwd)  # b5ef5feaf160038526b424e53a6fad9c

6. 动态加盐

  • 使用用户名的一部分 或者 直接使用整个用户名作为盐

import hashlib

username = input('用户名:')
password = input('密码:')

md5 = hashlib.md5(bytes(username, encoding='utf-8'))  # 以用户名作为动态的盐
md5.update(bytes(password, encoding='utf-8'))
pwd = md5.hexdigest()
print(pwd)

7. 练习

  • 登录验证

import hashlib

# 用户名和密码应该从文件或者数据库中获取出来,这里为了方便所以写死在这里
usn = 'Kevin'
c_pwd = '54cf3f7e747ca9d7640f241ce949e565'

username = input('用户名:')
password = input('密码:')

md5 = hashlib.md5(bytes(username, encoding='utf-8'))  # 用用户名作为盐
md5.update(bytes(password, encoding='utf-8'))
password = md5.hexdigest()

if username == usn and password == c_pwd:
    print('登录成功')
else:
    print('登录失败')

  • 对一个文件进行摘要算法且需要分次 update(),最后计算出这个文件的md5值。

import hashlib

def file(name):
    with open(name, encoding='utf-8') as f:
        yield from f

def ciphertext_fn(f):
    md5 = hashlib.md5()
    for i in f:
        md5.update(bytes(i, encoding='utf-8'))
    return md5.hexdigest()

f = file('log.txt')
ciphertext = ciphertext_fn(f)
print(ciphertext)  # 14b8cc85594b2cb47e5c1fac1ccce64c